/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package portelogiche;

import java.util.ArrayList;
import org.jgraph.graph.DefaultEdge;
import org.jgrapht.alg.CycleDetector;
import org.jgrapht.graph.DefaultDirectedGraph;
import org.jgrapht.traverse.TopologicalOrderIterator;

/**
 *
 * @author danielederuschi
 */
public class PorteLogicheSemantic {
        
        public  PorteLogicheParser plp;
        public  ArrayList SemanticErrors = new ArrayList();
        public  ArrayList outputArrayList = new ArrayList();
        public  ArrayList inputArrayList = new ArrayList();
        public  ArrayList msgArrayList = new ArrayList();
        public  ArrayList checkArrayList = new ArrayList();
	
	
	
	
	
	public PorteLogicheSemantic(PorteLogicheParser plp){
        
        this.plp = plp;
			
    }
    
	
        public DefaultDirectedGraph<String, DefaultEdge> CheckTables(){
             
                      CycleDetector<String, DefaultEdge> cycleDetector;
                      DefaultDirectedGraph<String, DefaultEdge> gr;

                      gr = new DefaultDirectedGraph<String, DefaultEdge> (DefaultEdge.class);

                      gr.addVertex("#");
                      gr.addVertex("#f");


                        boolean check1 = false;
                        boolean check2 = true;
                        boolean check3 = true;
                        boolean check4 = false;
                        boolean check5 = false;
                        boolean check6 = false;
                        boolean check7 = false;

                        int n;
                        int t;

                        for (n=0;n<plp.Ports.size();n++){
                        //Controllo semantico 3 verifica se la porta ha un loop su se stessa
                        if( plp.Ports.get(n).CheckEquals()){ 
                            check3=false;  
                            String er = "Self Loop" + plp.Ports.get(n).toString();
                            SemanticErrors.add(er);
                            checkArrayList.add(er);
                        }

                        // Controllo semanticao 6 verifica se esiste almeno un Ingresso #
                        if(  plp.Ports.get(n).input1.equals("#")||plp.Ports.get(n).input2.equals("#"))  {check6=true;}
                        // Controllo semanticao 7 verifica se esiste almeno un Uscita # 
                        if(  plp.Ports.get(n).output.equals("#")){  check7 = true;     }


                        // Inserimento in Array per la verifica di corrispondenza tra uscite e ingressi    
                        if (!plp.Ports.get(n).output.equals("null")&&!plp.Ports.get(n).output.equals("#")&&!outputArrayList.contains(plp.Ports.get(n).output)){
                        outputArrayList.add(plp.Ports.get(n).output);
                        }
                        if (!plp.Ports.get(n).input1.equals("null")&&!plp.Ports.get(n).input1.equals("#")&&!inputArrayList.contains(plp.Ports.get(n).input1)){
                        inputArrayList.add(plp.Ports.get(n).input1);
                        }
                        if (!plp.Ports.get(n).input2.equals("null")&&!plp.Ports.get(n).input2.equals("#")&&!inputArrayList.contains(plp.Ports.get(n).input2)){
                        inputArrayList.add(plp.Ports.get(n).input2);
                        }
                                                    
                                                   
                                                    
                                                    
                                                    if (!plp.Ports.get(n).output.equals("#")){

                                                          for (t=n;t<plp.Ports.size();t++){
                                                   // Controlla semantico 2 verifica se tutte le porte hanno uscite NUOVE 
                                                   // Non controlla le porte che hanno l'uscita finale # perch sono emmesse ripetizioni
                                                            if(plp.Ports.get(t).output.equals(plp.Ports.get(n).output)&&t!=n){
                                                                String se = plp.Ports.get(n).toString()+" same output name of "+
                                                                            plp.Ports.get(t).toString();
                                                                SemanticErrors.add(se);
                                                                checkArrayList.add(se);
                                                                check2 = false;
                                                            }
                                                          }      
                                                      }     
                                                          
                                                   // aggiunta all'albero per il controllo dei cicli   
                                                    String outmod;
                                                    // modifica l'etichetta per differenziare inizializzazione e finalizzazione del #       
                                                    if( plp.Ports.get(n).output.equals("#")){
                                                        outmod = "#f";
                                                    }
                                                    else{
                                                        outmod = plp.Ports.get(n).output;
                                                    }
                                                    
                                                    
                                                    // Controllo degli Archi di una porta di UNARIA 
                                                    if(plp.Ports.get(n).portType.equals("NOT")){
                                                        
                                                        int j;
                                                        String tempoutmod;
                                                        String thisport, otherport;
                                                        thisport = plp.Ports.get(n).portType+";"+plp.Ports.get(n).input1+";"+outmod;
                                                        gr.addVertex(thisport);
                                                       

                                                        //Aggiunge archi di inizializzazione e di chiusura possibilit di SKIP
                                                        if(plp.Ports.get(n).input1.equals("#")){ 
                                                            gr.addEdge("#", thisport); 

                                                        }
                                                        if(plp.Ports.get(n).output.equals("#")){ 
                                                            gr.addEdge(thisport, "#f");

                                                        }
                                                        
                                                        for (j=n;j<plp.Ports.size();j++){
                                                          if( plp.Ports.get(j).output.equals("#")){
                                                                    tempoutmod = "#f";
                                                                }
                                                                 else{
                                                                    tempoutmod = plp.Ports.get(j).output;
                                                                }
                                                          if(plp.Ports.get(j).portType.equals("NOT")){
                                                                    otherport = plp.Ports.get(j).portType+";"+plp.Ports.get(j).input1+";"+tempoutmod;
                                                                    gr.addVertex(otherport);  

                                                        
                                                                }
                                                                else{
                                                                    otherport = plp.Ports.get(j).portType+";"+plp.Ports.get(j).input1+";"+plp.Ports.get(j).input2+";"+tempoutmod;
                                                                    gr.addVertex(otherport);


                                                                }

                                                          
                                                          // inserisce L'arco in ingresso della porta NOT ei il nodo sorgente di questo arco
                                                          if(plp.Ports.get(n).input1.equals(plp.Ports.get(j).output)&&j!=n&&!plp.Ports.get(n).input1.equals("#")){
                                                                
                                                                gr.addEdge(otherport, thisport);
                                                            
                                                          }
                                                          if(plp.Ports.get(n).output.equals(plp.Ports.get(j).input1)&&j!=n&&!plp.Ports.get(n).output.equals("#")){
                                                                
                                                                gr.addEdge(thisport, otherport);
                                                             
                                                                       
                                                          }
                                                            
                                                          if(!plp.Ports.get(j).portType.equals("NOT")){
                                                                if(plp.Ports.get(n).output.equals(plp.Ports.get(j).input2)&&j!=n&&!plp.Ports.get(n).output.equals("#")){
                                                                
                                                                gr.addEdge(thisport, otherport); 
                                                              
                                                                }
                                                          }
                                                          
                                                          
                                                            
                                                        }

                                                    } // Controllo degli Archi delle porte BINARIE
                                                    else{
                                                        
                                                        int j;
                                                        String tempoutmod;
                                                        String thisport, otherport;
                                                        thisport = plp.Ports.get(n).portType+";"+plp.Ports.get(n).input1+";"+plp.Ports.get(n).input2+";"+outmod;
                                                        gr.addVertex(thisport);
                                                        //Aggiunge archi di inizializzazione e di chiusura possibilit di SKIP
                                                        if(plp.Ports.get(n).input1.equals("#")){ 
                                                            gr.addEdge("#", thisport);  
                                                            
                                                        }
                                                        if(plp.Ports.get(n).input2.equals("#")){ 
                                                            gr.addEdge("#", thisport);  
                                                           
                                                        }
                                                        if(plp.Ports.get(n).output.equals("#")){ 
                                                            gr.addEdge(thisport, "#f");  
                                                      
                                                        }
                                                        
                                                        
                                                        for (j=n;j<plp.Ports.size();j++){
                                                          if( plp.Ports.get(j).output.equals("#")){
                                                                    tempoutmod = "#f";
                                                                }
                                                                 else{
                                                                    tempoutmod = plp.Ports.get(j).output;
                                                                }
                                                          if(plp.Ports.get(j).portType.equals("NOT")){
                                                                    otherport = plp.Ports.get(j).portType+";"+plp.Ports.get(j).input1+";"+tempoutmod;
                                                                    gr.addVertex(otherport); 

                                                                }
                                                                else{
                                                                    otherport = plp.Ports.get(j).portType+";"+plp.Ports.get(j).input1+";"+plp.Ports.get(j).input2+";"+tempoutmod;
                                                                    gr.addVertex(otherport);

                                                                }
                                                            
                                                          // inserisce L'arco in ingresso della porta BINARIA ei il nodo sorgente di questo arco
                                                          if(plp.Ports.get(n).input1.equals(plp.Ports.get(j).output)&&j!=n&&!plp.Ports.get(n).input1.equals("#")){
                                                             
                                                                gr.addEdge(otherport, thisport);
                                                              
                                                          }
                                                          if(plp.Ports.get(n).input2.equals(plp.Ports.get(j).output)&&j!=n&&!plp.Ports.get(n).input2.equals("#")){
                                                      
                                                                gr.addEdge(otherport, thisport);
                                                             
                                                          }
                                                          if(plp.Ports.get(n).output.equals(plp.Ports.get(j).input1)&&j!=n&&!plp.Ports.get(n).output.equals("#")){
                                                              
                                                                gr.addEdge(thisport, otherport);
                                                          }
                                                            
                                                          if(!plp.Ports.get(j).portType.equals("NOT")){
                                                                if(plp.Ports.get(n).output.equals(plp.Ports.get(j).input2)&&j!=n&&!plp.Ports.get(n).output.equals("#")){
                                                                gr.addEdge(thisport, otherport);
                                                                
                                                                }
                                                          }
                                                        }
                                                    }
                                                    }

                                                    // Controllo semantico 1 verifica se tutte le porte hanno ingressi definiti
                                                    check1 = outputArrayList.containsAll(inputArrayList);
                                                    ArrayList tempOutputArrayList = new ArrayList();
                                                    tempOutputArrayList.addAll(outputArrayList);
                                                    // Controllo semantico 4 verifica se tutte le uscite sono usate come ingressi
                                                    check4 = inputArrayList.containsAll(outputArrayList);
                                                    ArrayList tempInputArrayList = new ArrayList();
                                                           tempInputArrayList.addAll(inputArrayList);


                                                  // Are there cycles in the dependencies.
                                                  cycleDetector = new CycleDetector<String, DefaultEdge>(gr);
                                                  // Cycle(s) detected.
                                                  if (cycleDetector.detectCycles()) {

                                                     msgArrayList.add(cycleDetector.findCycles());
                                                     msgArrayList.add("Cycles detected.");
                                                     check5= false;

                                                  }
                                                  // No cycles.  Just output properly ordered vertices.
                                                  else {
                                                     String v;
                                                     TopologicalOrderIterator<String, DefaultEdge> orderIterator;
                                             
                                                     orderIterator =
                                                        new TopologicalOrderIterator<String, DefaultEdge>(gr);
                                                     check5=true;
                                                     msgArrayList.add("\nPort Ordering:\n");
                                                     
                            
                                                     while (orderIterator.hasNext()) {
                                                       
                                                        v = orderIterator.next();

                                                        msgArrayList.add(v+"\n");
                                                     }
                                                  }   
                                
                                                  
                                                    msgArrayList.add("\n1) All input are defined: "+check1+"\n");
                                                    msgArrayList.add("\n2) All output are not duplicated: "+check2+"\n");
                                                    msgArrayList.add("\n3) All Ports are free of self loop: "+check3+"\n");
                                                    msgArrayList.add("\n4) All output are wired: "+check4+"\n");
                                                    msgArrayList.add("\n5) The graph is a DAG (direct acyclic grap): "+check5+"\n" );
                                                    msgArrayList.add("\n6) Graph is initialized: "+check6+"\n");
                                                    msgArrayList.add("\n7) Graph is finalized: "+check7+"\n");
                                                    msgArrayList.add("\n*********** "+plp.Ports.size() +" Ports Parsed********************\n");
                                                    msgArrayList.add("\n"+plp.Ports.toString()+"\n");
                                                    
                                                    msgArrayList.add(outputArrayList.toString());
                                                    msgArrayList.add(inputArrayList.toString());


                                                    if (!check1){
                                                        tempInputArrayList.removeAll(outputArrayList);
                                                    SemanticErrors.add("Input not defined: "+tempInputArrayList.toString());
                                                    checkArrayList.add("Input not defined: "+tempInputArrayList.toString());
                                                    }




                                                    if (!check4){
                                                        tempOutputArrayList.removeAll(inputArrayList);
                                                    SemanticErrors.add("Output not used: "+tempOutputArrayList.toString());
                                                    checkArrayList.add("Output not used: "+tempOutputArrayList.toString());
                                                    }
                                                    


                                                    if (!check5){
                                                    SemanticErrors.add("Cycles detected");
                                                    checkArrayList.add("Cycles detected");
                                                    }

                                                    if (!check6){
                                                    SemanticErrors.add("Graph is not initalized");
                                                    checkArrayList.add("Graph is not initalized");
                                                    }

                                                    if (!check7){
                                                    SemanticErrors.add("Graph is not finalized");
                                                    checkArrayList.add("Graph is not finalized");
                                                    }
                                                    return gr;
    }        
    

}
